package upload

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"ser1/config"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/rs/xid"
)

// UploadFileFromContext 从gin.Context上传文件的方法
// directory: 项目目录的文件夹路径名称
// c: gin.Context
// allowedTypes: 允许的文件类型数组，如果为空则允许所有类型
func UploadFileFromContext(directory string, c *gin.Context, allowedTypes []string) (*File, error) {
	// 获取上传的文件
	file, err := c.FormFile("file")
	if err != nil {
		return nil, fmt.Errorf("未找到上传的文件: %v", err)
	}

	// 读取文件内容
	src, err := file.Open()
	if err != nil {
		return nil, fmt.Errorf("打开上传文件失败: %v", err)
	}
	defer src.Close()

	// 读取文件数据
	fileData, err := io.ReadAll(src)
	if err != nil {
		return nil, fmt.Errorf("读取文件数据失败: %v", err)
	}

	// 调用UploadFile方法
	result, err := UploadFile(directory, file.Filename, fileData, allowedTypes)
	if err != nil {
		return nil, fmt.Errorf("上传文件失败: %v", err)
	}

	return result, nil
}

// UploadFile 封装的上传方法
// directory: 项目目录的文件夹路径名称
// filename: 文件名
// fileData: 文件数据
// allowedTypes: 允许的文件类型数组，如果为空则允许所有类型
func UploadFile(directory string, filename string, fileData []byte, allowedTypes []string) (*File, error) {
	// 获取上传目录配置
	uploadDir := config.GetField("UPLOAD_DIR")
	if uploadDir == "" {
		uploadDir = "./uploads"
	}

	// 构建完整路径
	fullPath := filepath.Join(uploadDir, directory)

	// 确保上传目录存在
	if err := os.MkdirAll(fullPath, os.ModePerm); err != nil {
		return nil, fmt.Errorf("创建上传目录失败: %v", err)
	}

	// 检查文件类型
	if len(allowedTypes) > 0 {
		// 获取文件扩展名
		ext := strings.ToLower(filepath.Ext(filename))
		allowed := false
		for _, t := range allowedTypes {
			if strings.ToLower(t) == ext {
				allowed = true
				break
			}
		}
		if !allowed {
			return nil, fmt.Errorf("不支持的文件类型: %s", ext)
		}
	}

	// 完整文件路径
	filePath := filepath.Join(fullPath, filename)

	// 写入文件
	if err := os.WriteFile(filePath, fileData, 0644); err != nil {
		return nil, fmt.Errorf("写入文件失败: %v", err)
	}

	// 获取文件大小
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		return nil, fmt.Errorf("获取文件信息失败: %v", err)
	}
	size := fileInfo.Size()

	// 检查数据库中是否已存在该文件记录
	var file File
	getDB().Where("directory = ? AND filename = ?", directory, filename).First(&file)

	// 构建相对路径
	relativePath := filepath.Join(directory, filename)

	if file.ID == 0 {
		// 数据库中不存在记录，创建新记录
		file = File{
			Path:      relativePath,
			Filename:  filename,
			Directory: directory,
			Size:      size,
		}
		if err := getDB().Create(&file).Error; err != nil {
			return nil, fmt.Errorf("创建数据库记录失败: %v", err)
		}
	} else {
		// 数据库中已存在记录，更新时间和文件大小
		updates := map[string]interface{}{
			"size":       size,
			"updated_at": time.Now(),
		}
		if err := getDB().Model(&file).Updates(updates).Error; err != nil {
			return nil, fmt.Errorf("更新数据库记录失败: %v", err)
		}
	}

	return &file, nil
}

// DeleteUpload 删除上传的文件及数据库记录
func DeleteUpload(id uint) error {
	var upload File
	err := getDB().First(&upload, id).Error
	if err != nil {
		return err
	}

	// 删除文件
	if err := os.Remove(upload.Path); err != nil && !os.IsNotExist(err) {
		return err
	}

	// 删除数据库记录
	return getDB().Delete(&upload).Error
}

// GetUpload 获取上传文件信息
func GetUpload(id uint) (*File, error) {
	var upload File
	err := getDB().First(&upload, id).Error
	if err != nil {
		return nil, err
	}
	return &upload, nil
}

// GetUploadsByUser 获取用户的所有上传文件
func GetUploadsByUser(userId uint) ([]File, error) {
	var uploads []File
	err := getDB().Where("user_id = ?", userId).Find(&uploads).Error
	return uploads, err
}

// generateUniqueFilename 生成唯一文件名
func generateUniqueFilename(originalName string) string {
	// 获取文件扩展名
	ext := filepath.Ext(originalName)
	// 生成XID
	guid := xid.New().String()
	// 获取当前时间戳
	timestamp := time.Now().Unix()

	// 组合新的文件名
	return fmt.Sprintf("%s_%d%s", guid, timestamp, ext)
}

// GetUploadDir 获取上传目录
func GetUploadDir() string {
	uploadDir := config.GetField("UPLOAD_DIR")
	if uploadDir == "" {
		uploadDir = "./uploads"
	}
	return uploadDir
}

func deleteFile(filePath string) error {
	print("删除文件: " + filePath + "\n")
	return os.Remove(filePath)
}
